/**
 * @file	proprietary_rf.c
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2021-01-08
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */
#include "sdk_config.h" 
#include "cst92f2x.h"
#include "mcu.h"
#include "gpio.h"
#include "clock.h"
#include "uart.h"
#include "pwrmgr.h"
#include "error.h"
#include "jump_function.h"
#include "rf_phy_driver.h"
#include "global_config.h"
#include "proprietary_rf.h"
#include "timer.h"


#define LL_RF_MIN_TIME      300

#define LL_HW_MODE_STX      (0x00)
#define LL_HW_MODE_SRX      (0x01)
#define LL_HW_MODE_TRX      (0x02)

uint16 g_rf_taskEvent;

__align(4) uint8_t  rfBufRx[256];
__align(4) uint8_t  rfBufTx[256];
__align(4) uint8_t  rfAckTx[256];

rfPktCfg_t s_pktCfg;
//rfPhyCfg_t s_phyCfg = {0};
//rfPhyStatus_t s_phyStatus;
uint32 RF_ISR_entry_time;
uint32 RF_go_entry_time;
//rf_Hdl_t rf_handler;

extern uint8 ll_hw_get_tr_mode(void);

/**
* @fn      	void rf_set_channel(uint8 rfChnIdx)
* @brief    set rf channel
* @param    rfChnIdx - rf channel index, index range:0~80, frequency range:2400~2480
* @return   none.
*/
static void rf_set_channel(uint8 rfChnIdx)
{

	if(g_rfPhyFreqOffSet>=0)
        PHY_REG_WT(0x400300b4, (g_rfPhyFreqOffSet<<16)+(g_rfPhyFreqOffSet<<8)+rfChnIdx);
    else
        PHY_REG_WT(0x400300b4, ((255+g_rfPhyFreqOffSet)<<16)+((255+g_rfPhyFreqOffSet)<<8)+(rfChnIdx-1) );

}

/**
* @fn      	void rf_hw_go(void)
* @brief    rf hardware start going to tx or rx
* @param    none.
* @return   none.
*/
static void rf_hw_go(void)
{
    //20190115 ZQ recorded ll re-trigger 
    if(llWaitingIrq==TRUE)
    {
        LOG("[PHY TRIG ERR]\n");
    }
    
	*(volatile uint32_t *)(LL_HW_BASE+ 0x14) = LL_HW_IRQ_MASK;	//clr  irq status
	*(volatile uint32_t *)(LL_HW_BASE+ 0x0c) = 0x0001;			//mask irq :only use mode done
	*(volatile uint32_t *)(LL_HW_BASE+ 0x00) = 0x0001;			//trig 

    uint8_t rfChnIdx = PHY_REG_RD(0x400300b4)&0xff;
    if(rfChnIdx<2) 
    {
        rfChnIdx=2;
    }
    else if(rfChnIdx>80)
    {
        rfChnIdx=80;
    }
    if(s_pktCfg.pktFmt==PKT_FMT_BLE2M)
        subWriteReg(0x40030094,7,0,RF_PHY_TPCAL_CALC(g_rfPhyTpCal0_2Mbps,g_rfPhyTpCal1_2Mbps,(rfChnIdx-2)>>1));
    else
        subWriteReg(0x40030094,7,0,RF_PHY_TPCAL_CALC(g_rfPhyTpCal0,g_rfPhyTpCal1,(rfChnIdx-2)>>1));

}

/**
* @fn      	void rf_hw_stop(void)
* @brief    rf hardware stop process
* @param    none.
* @return   none.
*/
static void rf_hw_stop(void)
{
//    uint8_t cnt=0;
	ll_hw_set_rx_timeout(1);
	ll_hw_set_rx_timeout_1st(1);
	ll_hw_set_loop_timeout(2);
//    while(llWaitingIrq)
//	{
//		WaitRTCCount(3);
//		cnt++;
//		if(cnt>100)
//		{
//			LOG("[PHY STOP ERR]\n");break;
//		}
//	};
}

/**
* @fn      	void rf_hw_set_srx(uint16 rxTimeOutUs)
* @brief    set rf in receive mode
* @param    rxTimeOutUs - receive timeout, unit:1us.
* @return   none.
*/
static void rf_hw_set_srx(uint16 rxTimeOutUs)
{
    ll_hw_set_rx_timeout(rxTimeOutUs);
    ll_hw_set_srx();
    ll_hw_set_trx_settle(   RF_HW_BB_DELAY,         // set BB delay                  
                            RF_HW_AFE_DELAY, 
                            RF_HW_PLL_DELAY);		  //RxAFE,PLL    
}

/**
* @fn      	void rf_hw_set_stx(void)
* @brief    set rf in transmit mode
* @param    none.
* @return   none.
*/
static void rf_hw_set_stx(void)
{
    ll_hw_set_stx();
    ll_hw_set_trx_settle(   RF_HW_BB_DELAY,         // set BB delay                  
                            RF_HW_AFE_DELAY, 
                            RF_HW_PLL_DELAY);		  //RxAFE,PLL    
}

/**
* @fn      	void rf_hw_set_trx(uint16 rxTimeOutUs) 
* @brief    set rf in transmit mode, after tranmit data, change to receive mode. It's often used in auto ack. 
* @param    rxTimeOutUs - receive timeout, unit:1us.
* @return   none.
*/
static void rf_hw_set_trx(uint16 rxTimeOutUs) 
{
    ll_hw_set_rx_timeout(rxTimeOutUs);
    ll_hw_set_trx();
    ll_hw_set_trx_settle(   RF_HW_BB_DELAY,         // set BB delay                  
                            RF_HW_AFE_DELAY, 
                            RF_HW_PLL_DELAY);		  //RxAFE,PLL    
}

/**
* @fn      	void rf_hw_timing_setting(void)
* @brief    set rf hardware timing.
* @param    none.
* @return   none.
*/
static void rf_hw_timing_setting(void)
{
    ll_hw_set_tx_rx_release	(10, 1);
	ll_hw_set_rx_tx_interval(60);		//T_IFS=150us for BLE 1M
	ll_hw_set_tx_rx_interval(66);		//T_IFS=150us for BLE 1M
	ll_hw_set_trx_settle(57, 8, 52);	//TxBB,RxAFE,PL
}

/**
* @fn      	uint8_t  rf_hw_write_tfifo(uint8_t* txPkt, uint16_t pktLen)
* @brief    write transmit fifo
* @param    txPkt - transmit packet buffer
			pktLen - transmit packet length
* @return   write word length.
*/
static uint8_t  rf_hw_write_tfifo(uint8_t* txPkt, uint16_t pktLen)
{
	int rdPtr,wrPtr,wrDepth,wlen;
	uint32_t *p_txPkt=(uint32_t *)txPkt;

	ll_hw_get_tfifo_info(&rdPtr,&wrPtr,&wrDepth);

	if((pktLen>0) && (wrDepth<512-LL_HW_FIFO_MARGIN))   // make sure write the longest pkt will not overflow
	{
		// make sure pktLen > 0

		wlen = 1+((pktLen-1)>>2);                       // calc the write tfifo count

		//--------------------------------------------------------------
		//write tfifo wlen-1 firstly
		while(p_txPkt<((uint32_t *)txPkt+wlen-1))
		{
			*(volatile uint32_t *)(LL_HW_TFIFO) = *p_txPkt++;
		}

		//--------------------------------------------------------------
		//calc the residue txPkt length
		//write tfifo last time
		int rduLen = pktLen&0x03;//pktLen%4

		if(rduLen==3)
		{
			*(volatile uint32_t *)(LL_HW_TFIFO) = *(uint16_t *)(txPkt+pktLen-3) | (txPkt[pktLen-1]<<16) ;
		}
		else if(rduLen==2)
		{
			*(volatile uint32_t *)(LL_HW_TFIFO) = *(uint16_t *)(txPkt+pktLen-2);
		}
		else if(rduLen==1)
		{
			*(volatile uint32_t *)(LL_HW_TFIFO) = *(txPkt+pktLen-1);
		}
		else
		{
			*(volatile uint32_t *)(LL_HW_TFIFO) = *p_txPkt;
		}


		return wlen;

	}
	else
	{

		return 0;
	}
}

/**
* @fn      	uint8_t  rf_hw_read_rfifo(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1)
* @brief    read receive fifo
* @param    txPkt - receive packet buffer
			pktLen - receive packet length
			pktFoot0, pktFoot1 - packet signal information
* @return   read word length.
*/
uint8_t  rf_hw_read_rfifo(uint8_t* rxPkt, uint16_t* pktLen, uint32_t* pktFoot0, uint32_t* pktFoot1)
{
	int       rdPtr, wrPtr, rdDepth, blen, wlen;
	uint32_t* p_rxPkt = (uint32_t *)rxPkt;

	ll_hw_get_rfifo_info(&rdPtr, &wrPtr, &rdDepth);

	if(rdDepth > 0)
	{
		*p_rxPkt++ = *(volatile uint32_t *)(LL_HW_RFIFO);

		blen    = rxPkt[1];                     //get the byte length for header
		wlen    = 1 + ((blen+2+3-1) >>2);    //+2 for Header, +3 for crc

		//compared the wlen and HW_WTR
		//20190115 ZQ
		if((wlen+2) >rdDepth)
		{
#if LL_PMCOUNTER_ENABLE
			g_pmCounters.ll_rfifo_read_err++;
#endif

			rxPkt[0]  = 0;
			*pktFoot0 = 0;
			*pktFoot1 = 0;
			*pktLen   = 0;

			return 0;
		}

		while(p_rxPkt < (uint32_t *)rxPkt + wlen)
		{
			*p_rxPkt++ = *(volatile uint32_t *)(LL_HW_RFIFO);
		}

		*pktFoot0   = *(volatile uint32_t *)(LL_HW_RFIFO);
		*pktFoot1   = *(volatile uint32_t *)(LL_HW_RFIFO);

		*pktLen     = blen + 2;


		return wlen;

	}
	else
	{

		rxPkt[0]  = 0;
		*pktFoot0 = 0;
		*pktFoot1 = 0;
		*pktLen   = 0;
		return 0;
	}
}



/**
* @fn      	void rf_hw_pktFmt_config(rfPktCfg_t *cfg)
* @brief    config rf hardware packet format
* @param    cfg - rf packet format.
* @return   none.
*/
void rf_hw_pktFmt_config(rfPktCfg_t *cfg)
{
	osal_memcpy(&s_pktCfg, cfg, sizeof(rfPktCfg_t));
    //baseband cfg
    rf_phy_bb_cfg(cfg->pktFmt);
    
    //pktfmt
    if(cfg->crcFmt==LL_HW_CRC_NULL)
    {
        //fix length mode ,no hw crc gen/check
        ll_hw_set_pktfmt(cfg->pduLen);
        ll_hw_ign_rfifo(LL_HW_IGN_NONE);
    }
    else
    {
        //crc
        ll_hw_set_crc_fmt(cfg->crcFmt,cfg->crcFmt);
        RF_SET_CRC_SEED(cfg->crcSeed);
        ll_hw_ign_rfifo(LL_HW_IGN_CRC);
    }
    
    //whiten
    RF_SET_WHITEN_SEED(cfg->wtSeed);
    //syncword 
    RF_SET_SYNCWORD(cfg->syncWord);
}

/**
* @fn      	void rf_hw_phy_config(rfPhyCfg_t *cfg)
* @brief    config rf hardware physical layer
* @param    cfg - rf physical layer parameter.
* @return   none.
*/
void rf_hw_phy_config(rfPhyCfg_t *cfg)
{
	osal_memcpy(&s_phyCfg, cfg, sizeof(rfPhyCfg_t));
}

/**
* @fn      	void rf_hw_channel_set(uint8 channel)
* @brief    config rf channel
* @param    channel - rf channel.
* @return   none.
*/
void rf_hw_channel_set(uint8 channel)
{
	s_phyCfg.rfChn = channel;
}

/**
* @fn      	void rf_tx_start(void)
* @brief    start RF transmit
* @param    none.
* @return   none.
*/
void rf_tx_start(void)
{
    rf_hw_stop();
	if(s_phyCfg.autoAck)
	{
		s_phyStatus = RF_PHY_ST_TRX_ONLY;
	}
    else
	{
		s_phyStatus = RF_PHY_ST_TX_ONLY;
	}
    HAL_ENTER_CRITICAL_SECTION();

    rf_hw_pktFmt_config(&s_pktCfg);
    rf_hw_timing_setting();
    
    rf_set_channel(s_phyCfg.rfChn);
    if(s_phyCfg.autoAck)
	{
        rf_hw_set_trx(s_phyCfg.rxAckTO);
	}
    else
	{
        rf_hw_set_stx();
	}

    ll_hw_rst_tfifo();
    ll_hw_rst_rfifo();
    set_max_length(0xff);
    
    //need updata rfBufTx
    rf_hw_write_tfifo(rfBufTx,rfBufTx[1]+2);

    rf_hw_go();
	RF_go_entry_time = read_current_fine_time();
    llWaitingIrq=TRUE;
    HAL_EXIT_CRITICAL_SECTION();
}

/**
* @fn      	void rf_rx_start(void)
* @brief    start RF receive
* @param    none.
* @return   none.
*/
void rf_rx_start(void)
{
    //rf_hw_stop();
    uint32_t time;
    if(s_phyCfg.bleEnable)
    {
        time = (AP_TIM1->CurrentCount)>>2;
        
        if(time > LL_RF_MIN_TIME)
        {
            time -= LL_RF_MIN_TIME;
            if(time > 0xFFFF)
            {
                time = 0xFFFF;
            }
        }
        else
        {
            return;
        }
    }
    else
    {
        time = s_phyCfg.rxOnlyTO;
    }
	s_phyStatus = RF_PHY_ST_RX_ONLY;
    HAL_ENTER_CRITICAL_SECTION();

    rf_hw_pktFmt_config(&s_pktCfg);
    rf_hw_timing_setting();
    
    rf_set_channel(s_phyCfg.rfChn);
    rf_hw_set_srx(time);

    ll_hw_rst_tfifo();
    ll_hw_rst_rfifo();
    set_max_length(0xff);
    
    rf_hw_go();
    llWaitingIrq=TRUE;
    HAL_EXIT_CRITICAL_SECTION();
}

/**
* @fn      	void rf_tx_ack_start(void)
* @brief    start RF ACK transmit
* @param    none.
* @return   none.
*/
void rf_tx_ack_start(void)
{
    if(s_phyCfg.bleEnable)
    {
        if(AP_TIM1->CurrentCount < 1200)
        {
            return;
        }
    }
	s_phyStatus = RF_PHY_ST_TX_ONLY;
	rf_hw_set_stx();

    ll_hw_rst_tfifo();
    ll_hw_rst_rfifo();
    
    //need updata rfBufTx
    rf_hw_write_tfifo(rfAckTx,rfAckTx[1]+2);

    rf_hw_go();
    llWaitingIrq=TRUE;
}

/**
* @fn      	void rf_stop(void)
* @brief    stop RF 
* @param    none.
* @return   none.
*/
void rf_stop(void)
{
	if(llWaitingIrq)
	{
		rf_hw_stop();
	}
}

/**
* @fn      	void rf_tx_buf_updata(uint8_t header, uint8_t length,  uint8_t* payload)
* @brief    update transmit buffer
* @param    header - information header
*			length - payload length
*			payload - payload buffer
* @return   none.
*/
void rf_tx_buf_update(uint8_t header, uint8_t length,  uint8_t* payload)
{
	rfBufTx[0] = header;
	rfBufTx[1] = length;
	if(length > 0)
	{
		osal_memcpy(&rfBufTx[2], payload, length);		//copy payload
	}
//    LOG("RF BUF Tx Dump:");
//    for(uint8_t i=0;i<rfBufTx[1]+2;i++)
//        LOG("%02x ",rfBufTx[i]);
//    LOG("\n");
}

/**
* @fn      	void rf_tx_ack_update(uint8_t header, uint8_t length,  uint8_t* payload)
* @brief    update ACK buffer
* @param    header - information header
*			length - payload length
*			payload - payload buffer
* @return   none.
*/
void rf_tx_ack_update(uint8_t header, uint8_t length,  uint8_t* payload)
{
	rfAckTx[0] = header;
	rfAckTx[1] = length;
	if(length > 0)
	{
		osal_memcpy(&rfAckTx[2], payload, length);		//copy payload
	}
//    LOG("RF ACK Tx Dump:");
//    for(uint8_t i=0;i<rfAckTx[1]+2;i++)
//        LOG("%02x ",rfAckTx[i]);
//    LOG("\n");
}

/**
* @fn      	uint32_t rf_rx_time_get(void)
* @brief    get rf receive time from start rx point to current point
* @param    none
* @return   receive time, unit is 1us.
*/
uint32_t rf_rx_time_get(void)
{
	return TIME_DELTA(RF_ISR_entry_time, RF_go_entry_time);
}

/**
* @fn      	rfPhyStatus_t rf_phy_status_get(void)
* @brief    get rf status
* @param    none
* @return   rf status, reference to rfPhyStatus_t
*/
rfPhyStatus_t rf_phy_status_get(void)
{
	return s_phyStatus;
}

void rf_irq_process(uint8_t tr_mode, uint32_t irq_status)
{
    uint16 foff;
    uint8  carrSens;
    uint8  rssi;
    rfEvent_t event;
    uint8 status = 0;
    
    if (tr_mode == LL_HW_MODE_STX  &&
          (s_phyStatus == RF_PHY_ST_TX_ONLY)
       )
    {
        if(rf_handler)
        {
            event.rfEvent = RF_EVT_TX_DONE;
            status = rf_handler(&event);
        }
    }
    else if(tr_mode == LL_HW_MODE_SRX  &&
          (s_phyStatus == RF_PHY_ST_RX_ONLY)
       )
    {
        //rf_phy_get_pktFoot(&rssi,&foff,&carrSens);
        if(irq_status & LIRQ_RTO)	//receive timeout
        {
            if(rf_handler)
            {
                event.rfEvent = RF_EVT_RX_TIMEOUT;
                status = rf_handler(&event);
            }
        }
        else if((irq_status & LIRQ_COK) || s_pktCfg.crcFmt==LL_HW_CRC_NULL)		//receive packet is correct or don't care CRC
        {
            uint16_t pktLen;
            uint32_t pktFoot0, pktFoot1; 
            rf_hw_read_rfifo(rfBufRx, &pktLen,&pktFoot0,&pktFoot1);

            rf_phy_get_pktFoot_fromPkt(pktFoot0,pktFoot1,
                                    &rssi,&foff,&carrSens);
            if(rf_handler)
            {
                event.rfEvent = RF_EVT_RX_DONE;
                
                event.header = rfBufRx[0];
                event.length = rfBufRx[1];
                event.pPayload = &rfBufRx[2];
                    
                event.rfFoff = foff;
                event.rfRssi = rssi;
                event.rfCarrSens = carrSens;
                
                status = rf_handler(&event);
            }
        }	
        else	//receive error packet
        {
            if(rf_handler)
            {
                event.rfEvent = RF_EVT_RX_PKT_ERR;
                status = rf_handler(&event);
            }
        }
    }
    else if(tr_mode == LL_HW_MODE_TRX  &&
          (s_phyStatus == RF_PHY_ST_TRX_ONLY)
       )
    {
        //rf_phy_get_pktFoot(&rssi,&foff,&carrSens);
        if(irq_status & LIRQ_RTO)	//receive timeout
        {
            if(rf_handler)
            {
                event.rfEvent = RF_EVT_TRX_TIMEOUT;
                status = rf_handler(&event);
            }
        }
        else if((irq_status & LIRQ_COK) || s_pktCfg.crcFmt==LL_HW_CRC_NULL)	//receive packet is correct or don't care CRC
        {

            uint16_t pktLen;
            uint32_t pktFoot0, pktFoot1; 
            rf_hw_read_rfifo(rfBufRx, &pktLen,&pktFoot0,&pktFoot1);

            rf_phy_get_pktFoot_fromPkt(pktFoot0,pktFoot1,
                                        &rssi,&foff,&carrSens);                              
            if(rf_handler)
            {
                event.rfEvent = RF_EVT_TRX_DONE;
                
                event.header = rfBufRx[0];
                event.length = rfBufRx[1];
                event.pPayload = &rfBufRx[2];
                    
                event.rfFoff = foff;
                event.rfRssi = rssi;
                event.rfCarrSens = carrSens;
                
                status = rf_handler(&event);
            }
        }
        else	//receive error packet
        {
            if(rf_handler)
            {
                event.rfEvent = RF_EVT_TRX_PKT_ERR;
                status = rf_handler(&event);
            }
        }
    }
    
    // post ISR process   
    if(!llWaitingIrq)
    {
        ll_hw_clr_irq();
    }
    if(status == 0)
    {
        s_phyStatus = RF_PHY_ST_IDLE;
    }
}
/**
* @fn      	void RF_IRQHandler(void)
* @brief    Interrupt Request Handler for RF Link Layer
* @param    none.
* @return   none.
*/
void RF_IRQHandler(void)
{
    uint8 mode;
    uint32_t irq_status;
    //uint32_t      T2, delay;

    RF_ISR_entry_time = read_current_fine_time();    
    
    irq_status = ll_hw_get_irq_status();
    
    if (!(irq_status & LIRQ_MD))          // only process IRQ of MODE DONE
    {
        ll_hw_clr_irq();                  // clear irq status
        return;
    }
    
    llWaitingIrq = FALSE;

    HAL_ENTER_CRITICAL_SECTION();   
            
    mode = ll_hw_get_tr_mode();   

    // ===================   mode TRX process 1
    rf_irq_process(mode, irq_status);
    HAL_EXIT_CRITICAL_SECTION();
}


